#include <stdio.h>      /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), bind(), and connect() */
#include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */
#include <stdlib.h>     /* for atoi() and exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */
#include <time.h>
#include <sys/time.h>
#include <linux/if_ether.h>
#include <netinet/tcp.h>
#include <linux/ip.h>
#include <iostream>
#include <fstream>
#include "ntcp.h"


using namespace std;

unsigned short dstPort = 1001;
unsigned short rcvPort = 1000;     	 /* Server receive port */
unsigned short ctrlPort = PORT;
char srcIP[] = "192.168.200.250";
int clntSock;
double FILESIZE = 138045015;

void HandleTCPClient( int ctrlSock);   /* TCP client handling function */

int main(int argc, char *argv[])
{
    	int ctrlSock;                    /* Socket descriptor for control */	
	struct sockaddr_in servAddr; /* Local address */
	struct sockaddr_in clntAddr; /* Client address */
    	unsigned int clntLen;            /* Length of client address data structure */

	if ((ctrlSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		DieWithError("control socket() failed!\n");
	}else{
		printf("control socket established!\n");
	}

	memset(&servAddr, 0, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAddr.sin_port = htons(ctrlPort);
	
	if(bind(ctrlSock, (struct sockaddr*)&servAddr, sizeof(struct sockaddr)) < 0){
		DieWithError("control socket bind() failed");
	} else {
		printf("control socket bind succeeds!\n");
	}
	
	if(listen(ctrlSock,MAXPENDING) < 0){
		DieWithError("control socket listen() failed");
	}else{
		printf("control socket listen port!\n");
	}
	
	clntLen = sizeof(clntAddr);
	if((clntSock = accept(ctrlSock, (struct sockaddr*)&clntAddr, &clntLen)) < 0) {
		DieWithError("accept fails");
	}
	
	HandleTCPClient(clntSock);
}

void HandleTCPClient(int ctrlSock) {
	struct ntcp_sock sock;
	char ctrlBuff[RCVBUFSIZE];
	int recvMsgSize=0;
	long fileSize = 0;
	long transSize = 0;
	struct sockaddr_in rcvSrcAddr;
	memset(&rcvSrcAddr, 0, sizeof(rcvSrcAddr));     /* Zero out structure */
	rcvSrcAddr.sin_family      = AF_INET;             /* Internet address family */
	rcvSrcAddr.sin_addr.s_addr = inet_addr(srcIP);   /* Server IP address */
	rcvSrcAddr.sin_port        = htons(rcvPort); /* Server port */
	
	socklen_t add_len = sizeof(struct sockaddr_in);

	/* Create socket for incoming connections */
    	if ( ntcp_create_sock(&sock, ctrlSock, &rcvSrcAddr, rcvPort, dstPort) < 0) {
        	DieWithError(" data socket() failed");
    	} else {
    		printf(" data socket established!\n");
    	}
	
	struct sockaddr_in addr;
	bzero(&addr,sizeof(struct sockaddr_in));
	addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(rcvPort);
	if(bind(sock.datasock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))< 0)
		DieWithError("Bind address failed");
	printf("server bind address succeeds!\n");

	char rcvBuffer[RCVBUFSIZE];        /* Buffer for echo string */
	rcvBuffer[RCVBUFSIZE] = 0;

	timeval start, stop;
	start.tv_sec = 0;
	
	FILE *fp;
	if((fp=fopen("output","wb"))==NULL){
		DieWithError("open output failed!\n");
	}
 	
	while((recvMsgSize = recv(ctrlSock, ctrlBuff, RCVBUFSIZE, 0)) > 0){
		if(strstr(ctrlBuff,"FILESIZE") != NULL){
			fileSize = atol(&ctrlBuff[9]);
			printf("get FILESIZE: %ld\n",fileSize);
			break;
		}
		memset(ctrlBuff,0,RCVBUFSIZE);
	};
	   	
/*	char begin[] = "BEGIN ";
	int beginlen = strlen(begin);
	if(send(ctrlSock, begin, beginlen,0) != beginlen){
		DieWithError("send begin cmd failed!");
	}
*/
	/* Receive message from client */
    	while ((recvMsgSize = ntcp_recvfrom(&sock, rcvBuffer, RCVBUFSIZE, 0,(struct sockaddr* )&rcvSrcAddr, &add_len)) > 0)
    	{
		// Initial start time
		if(start.tv_sec == 0) gettimeofday(&start, NULL);

		if(fwrite(rcvBuffer, recvMsgSize, 1, fp) != 1){
		    fclose(fp);	
		    DieWithError("file write error\n");
		}

		transSize += recvMsgSize;
		if(transSize == fileSize){
		    printf("file transfer finish!\n");
		    break;
		}
		memset(&rcvBuffer,0,sizeof(rcvBuffer));
	};	
	
	gettimeofday(&stop, NULL);
	double during = (stop.tv_sec - start.tv_sec) + (double)(stop.tv_usec - start.tv_usec) / 1000000.0;
	cout<<"transfer time "<<during<<endl;
	double v = FILESIZE * 8.0/during/1000000.0;
	cout<<"v "<<v<<endl;
    	fclose(fp);
	ntcp_close(&sock);
}

